﻿using System;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using XLua;

//加解密使用base64转码方法，ECB模式，PKCS5Padding填充，密码必须是16字节
//模式:Java的ECB对应C#的System.Security.Cryptography.CipherMode.ECB
//填充方法:Java的PKCS5Padding对应C#System.Security.Cryptography.PaddingMode.PKCS7
//编码指定采用UTF-8，有需要其他编码方法的可自行扩展

namespace UMT.Framework.Security
{
    //协议加解密
    public class EncryptAES
    {
        private static byte[] m_privateKey;
        private static System.Security.Cryptography.ICryptoTransform m_ICTEncryptor;

       /// <summary>
        /// SetKey
        /// </summary>
        public static void SetKey(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                Debug.LogError("AES Key Error! ->" + key);
                return;
            }

            byte[] publicKey = null;
            try
            {
                publicKey = Convert.FromBase64String(key);
            }
            catch
            {
                Debug.LogWarning("SetKey publicKey is invalid.");
                return;
            }
            byte[] randomKey = DiffieHellman.GetSharedSecret(m_privateKey, publicKey);
            byte[] subKey = new byte[16];
            Array.Copy(randomKey, 0, subKey, 0, 16); //取高16位最为最终秘钥
            m_privateKey = null;

            if (m_ICTEncryptor != null)
            {
                m_ICTEncryptor.Dispose();
            }

            System.Security.Cryptography.RijndaelManaged rijndaelManaged = new System.Security.Cryptography.RijndaelManaged
            {
                Key = subKey,
                Mode = System.Security.Cryptography.CipherMode.ECB,
                Padding = System.Security.Cryptography.PaddingMode.PKCS7
            };

            m_ICTEncryptor = rijndaelManaged.CreateEncryptor();
        }

        public static ICryptoTransform GetCryptoTransform()
        {
            return m_ICTEncryptor;
        }
        
        public static void DisposeCryptoTransform()
        {
            if (m_ICTEncryptor != null)
            {
                m_ICTEncryptor.Dispose();
                m_ICTEncryptor = null;
            }
        }


        /// <summary>
        /// AESEncrypt
        /// </summary>
        [BlackList]
        public static byte[] AESEncrypt(byte[] data)
        {
            if (data.Length == 0 || m_ICTEncryptor == null)
            {
                if (Debug.unityLogger.logEnabled)
                {
                    Debug.LogError("Encrypt Parameter Error,data.Length: " + data.Length);
                }
                return null;
            }
            else
            {
                return m_ICTEncryptor.TransformFinalBlock(data, 0, data.Length);
            }
        }

        /// <summary>
        /// AESEncrypt
        /// </summary>
        [BlackList]
        public static string AESEncrypt(string data, string key)
        {
            if (string.IsNullOrEmpty(data) || string.IsNullOrEmpty(key))
            {
                return null;
            }

            Byte[] toEncryptArray = Encoding.UTF8.GetBytes(data);
            System.Security.Cryptography.RijndaelManaged rm = new System.Security.Cryptography.RijndaelManaged
            {
                Key = Encoding.UTF8.GetBytes(key),
                Mode = System.Security.Cryptography.CipherMode.ECB,
                Padding = System.Security.Cryptography.PaddingMode.PKCS7
            };

            System.Security.Cryptography.ICryptoTransform cTransform = rm.CreateEncryptor();
            Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }

        /// <summary>
        /// AESDecrypt
        /// </summary>
        private static byte[] AESDecrypt(byte[] data, string key)
        {
            if (data.Length == 0 || string.IsNullOrEmpty(key))
            {
                if (Debug.unityLogger.logEnabled)
                {
                    Debug.LogError("Encrypt Parameter Error");
                }
                return null;
            }

            System.Security.Cryptography.RijndaelManaged rm = new System.Security.Cryptography.RijndaelManaged
            {
                Key = Encoding.UTF8.GetBytes(key),
                Mode = System.Security.Cryptography.CipherMode.ECB,
                Padding = System.Security.Cryptography.PaddingMode.PKCS7
            };

            System.Security.Cryptography.ICryptoTransform cTransform = rm.CreateDecryptor();
            string a = string.Empty;
            a.GetHashCode();
            return cTransform.TransformFinalBlock(data, 0, data.Length);
        }

        /// <summary>
        /// AESDecrypt
        /// </summary>
        [BlackList]
        public static string AESDecrypt(string data, string key)
        {
            if (string.IsNullOrEmpty(data) || string.IsNullOrEmpty(key))
            {
                return null;
            }

            Byte[] toEncryptArray = Convert.FromBase64String(data);
            System.Security.Cryptography.RijndaelManaged rm = new System.Security.Cryptography.RijndaelManaged
            {
                Key = Encoding.UTF8.GetBytes(key),
                Mode = System.Security.Cryptography.CipherMode.ECB,
                Padding = System.Security.Cryptography.PaddingMode.PKCS7
            };

            System.Security.Cryptography.ICryptoTransform cTransform = rm.CreateDecryptor();
            Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            return Encoding.UTF8.GetString(resultArray);
        }

        /// <summary>
        /// DiffieHellman
        /// </summary>
        public static string GetDiffieHellmanKey()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0);
            System.Random random = new System.Random(ts.Milliseconds);
            byte[] rawKey = new byte[32];
            for (int i = 0; i < 32; i++)
            {
                rawKey[i] = (byte)random.Next(256);
            }

            m_privateKey = DiffieHellman.ClampPrivateKey(rawKey);
            return Convert.ToBase64String(DiffieHellman.GetPublicKey(m_privateKey));
        }

        public static string GetSha256(string value)
        {
            SHA256Managed managed = new SHA256Managed();
            byte[] bytes = managed.ComputeHash(Encoding.UTF8.GetBytes(value));
            return BitConverter.ToString(bytes).Replace("-", "").ToLower();
        }

        /// <summary>
        /// 获取一个字符串的Base64编码
        /// </summary>
        /// <param name="value">字符串</param>
        /// <param name="codeType">编码格式</param>
        /// <returns></returns>
        public static string GetBase64(string value, string codeType)
        {
            string encode = "";
            try
            {
                byte[] bytes = Encoding.GetEncoding(codeType).GetBytes(value);
                encode = Convert.ToBase64String(bytes);
            }
            catch
            {
                encode = value;
            }
            return encode;
        }

        /// <summary>
        /// 获取字符串的md5值
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns></returns>
        public static string GetMd5(string value)
        {
            string cl = value;
            StringBuilder pwd = new StringBuilder();
            MD5 md5 = MD5.Create();
            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
            for (int i = 0; i < s.Length; i++)
            {
                // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母，如果使用大写（X）则格式后的字符是大写字符
                pwd.Append(s[i].ToString("X2"));
            }
            return pwd.ToString().ToLower();
        }
    }
}